package com.anotherrobbo.armedia.server;

import java.io.InputStream;
import java.util.Properties;

import com.anotherrobbo.armedia.engine.PlayerEngine;
import com.anotherrobbo.armedia.server.console.ConsoleReader;
import com.anotherrobbo.armedia.server.socket.SocketReader;

public class MediaServer {
	
	private static final String PROP_ENGINE_CLASS = "engine.class";
	private static final String PROP_LISTEN_PORT = "listen.port";

	private static MediaServer instance;
	
	private PlayerEngine playerEngine;
	private int port;
	
	public static void main(String[] args) {
		getInstance("/armedia.properties");
	}
	
	public static MediaServer getInstance(String propsPath) {
		if (propsPath != null && instance == null) {
			try {
				Properties props = new Properties();
				InputStream is = MediaServer.class.getResourceAsStream(propsPath);
				props.load(is);
				instance = new MediaServer(props);
			} catch (Exception e) {
				throw new IllegalArgumentException("Unable to load properties file: " + propsPath, e);
			}
		}
		return getInstance();
	}

	public static MediaServer getInstance() {
		if (instance != null) {
			return instance;
		}
		throw new IllegalStateException("instance did not already exist and no properties file path was provided");
	}

	public PlayerEngine getPlayerEngine() {
		return playerEngine;
	}

	MediaServer(Properties props) {
		loadProps(props);
		new ConsoleReader(playerEngine).start();
		new SocketReader(port, playerEngine).start();
	}
	
	void loadProps(Properties props) {
		loadEngine(props.getProperty(PROP_ENGINE_CLASS));
		this.port = Integer.parseInt(props.getProperty(PROP_LISTEN_PORT));
	}

	void loadEngine(String engineClassName) {
		try {
			Class<PlayerEngine> engineClass = (Class<PlayerEngine>) Class.forName(engineClassName);
			if (PlayerEngine.class.isAssignableFrom(engineClass)) {
				this.playerEngine = engineClass.newInstance();
			} else {
				throw new IllegalArgumentException("Class: " + engineClassName + " does not implement PlayerEngine");
			}
		} catch (ClassNotFoundException cnf) {
			throw new IllegalArgumentException("Class: " + engineClassName + " not found", cnf);
		} catch (InstantiationException ie) {
			throw new IllegalArgumentException("Class: " + engineClassName + " could not be instantiated", ie);
		} catch (IllegalAccessException iae) {
			throw new IllegalArgumentException("Class: " + engineClassName + " could not be instantiated", iae);
		}
	}

}
